﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Threading;
using System.Windows.Forms;
using AGB;
using AGB.IDemonbuddy;
using AGB.Modules;
using D3.Pathing;
using Zeta;
using Zeta.Common;
using Zeta.CommonBot;
using Zeta.CommonBot.Logic;
using Zeta.Internals.Actors;
using Zeta.Navigation;
using Zeta.TreeSharp;
using Action = System.Action;

namespace AGB.Managerial
{
    public struct PulseArgs
    {
        public enum PulseTypes
        {
            
        }

        public Dictionary<string, object> Params;

        /* What's this? 
         *
         * Maybe you want to pass a context variable in the pulse or differentiate pulse behavior on the pulse type
         * 
         */

    }

    /// <summary>
    /// The main class, all information is stored here.  All behaviors are tied together here
    /// </summary>
    public static class BotManager
    {
        #region " Public members "

        public delegate void PriorityAction();
       
        // WE NEED THESE FOR NAMED ACCESS
        public static Arms Arms;
        public static Legs Legs;
        public static Face Face;
        public static CerebralCortex CerebralCortex;
        public static FrontalLobe FrontalLobe;
        public static Lobby Lobby;
        public static Action BotManagerTick;
        public static Composite BotManagerBehavior;
        public static bool IsRunning = true;
        #endregion

        #region " Private members "

        public static UnitManager UnitManager;
        private static List<Module> Modules; 
        private static Thread Thread;
        private static long _lastTick = Environment.TickCount;
        private static int _startTick = 0;
        private static Queue<PriorityAction> Actions;
        private static Action MultiverseTick;
        private const int PulseDelay = 200;
        #endregion


        public static void Stop()
        {

            foreach (var module in Modules)
            {
                module.Unload();
            }

            //if (_Demonbuddy.aWindow != null) _Demonbuddy.aWindow.Close();
            Multiverse.Clear();
            Application.Exit();
            
            
        }

        public static bool IsInGameEx()
        {
            bool inGame = false;

            if (ZetaDia.Actors == null)
                return false;
            try
            {
                if (ZetaWrap.IsInGame() && !ZetaWrap.IsLoadingWorld())
                    inGame = true;
            }
            catch (Exception e)
            {
                Logging.WriteVerbose("We failed on IsInGame, no worries.");

            }

            return inGame;
        }

        public static void AddAction(PriorityAction action)
        {
            Actions.Enqueue(action);
        }
        //Kills Demonbuddys GameStats
        public static void KillStats()
        {
            

            /*foreach (var module in typeof(Zeta.CommonBot.GameStats).GetFields(BindingFlags.Static))
            {
                Logging.Write("Fieldname");
                Logging.Write(module.Name);
            }*/
            /*FieldInfo f1 = typeof(Zeta.CommonBot.GameStats).GetField("PropertyChanged", BindingFlags.Instance | BindingFlags.Public);
            object obj = f1.GetValue(Zeta.CommonBot.GameStats.Instance);
            PropertyInfo pi = Zeta.CommonBot.GameStats.Instance.GetType().GetProperty("Events", BindingFlags.Public | BindingFlags.Instance);
            EventHandlerList list = (EventHandlerList)pi.GetValue(Zeta.CommonBot.GameStats.Instance, null);
            list.RemoveHandler(obj, list[obj]);*/
        }

        /// <summary>
        /// Loads all modules by Proxy
        /// Starts BotManager thread
        /// </summary>
        public static void Start()
        {


            _startTick = Environment.TickCount;
            Multiverse.init();

            IsRunning = true;

            //MultiverseTick = new Action(UpdateMaps);

            Actions = new Queue<PriorityAction>();
            UnitManager = new UnitManager();

            // WE NEED THESE FOR NAMED ACCESS
            Face = new Face();
            Legs = new Legs();
            CerebralCortex = new CerebralCortex();
            FrontalLobe = new FrontalLobe();
            Arms = new Arms();
            Lobby = new Lobby();

            Modules = new List<Module>();

            /* We like these modules names */
            Modules.Add(Lobby);

            /* These module names are subject to change */

            Modules.Add(Arms);
            Modules.Add(Face);
            Modules.Add(Legs);

            Modules.Add(CerebralCortex);
            Modules.Add(FrontalLobe);

            Logging.Write("Modules Starting");

            foreach (var module in Modules)
            {
                Logging.Write("Starting: " + module.Name);
                module.Start();
            }

            BotManagerBehavior = new Zeta.TreeSharp.Action(delegate
                                                               { 



                                                                   Tick();
                                                                   GameEvents.Update();
                                                                   return RunStatus.Success;
                                                               });
        }

        private static long NavUpdate = Environment.TickCount;

        private static void UpdateMaps()
        {
            Multiverse.GetCurrentMap().CheckForNewScenes();
        }

        private static void Tick()
        {
            //0xB4433DA3F648A992 GAME IN PROCESS
            int a = Environment.TickCount;

            while (Actions.Count > 0) Actions.Dequeue().Invoke();

            if (IsInGameEx())
            {
                DoPulse();
            }
        }

        /// <summary>
        /// Top Layer Pulse should only be initiated from inside.
        /// </summary>
        private static void DoPulse()
        {
            _lastTick = Environment.TickCount;
            //UpdateMaps();
            UnitManager.Tick();
            foreach (var module in Modules)
            {
                module.Pulse(new PulseArgs());
            }
        }

    }
}